package frontend.pages.worklog.daily;

import backend.model.admin.Employee;
import backend.model.other.User;
import backend.model.worklog.WorkLog;
import backend.service.other.UserService;
import backend.service.worklog.WorkLogService;
import frontend.components.other.EmployeeSelectionPanel;
import frontend.components.other.NoSelectionPanel;
import frontend.core.TimeTrackingWebApplication;
import frontend.core.TimeTrackingWebSession;
import frontend.model.worklog.WorkLogUIModel;
import frontend.pages.base.BaseWebPage;
import shared.util.CalendarUtils;
import frontend.components.other.UserInputCallableAction;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.extensions.ajax.markup.html.tabs.AjaxTabbedPanel;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.request.resource.ContextRelativeResource;
import org.wicketstuff.annotation.mount.MountPath;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import static shared.other.UserRolesDefinition.*;

@MountPath("dailyWorkLog")
@AuthorizeInstantiation(value = {EMPLOYEE_ROLE_KEY, FOREMAN_ROLE_KEY, ADMIN_ROLE_KEY})
public class DailyWorkLogPage extends BaseWebPage {

    public static final String HELP_PANEL_TEXT = "contextualHelp.dailyWorkLogPage.text";
    public static final String ADD_WORK_LOG_TAB_TITLE = "pages.dailyWorkLogPage.add.title";
    public static final String EDIT_WORK_LOG_TAB_TITLE = "pages.dailyWorkLogPage.edit.title";

    private WorkLogUIModel workLogUIModel = new WorkLogUIModel();
    private WebMarkupContainer workLogFormContainer;
    private List<WorkLog> workLogList = new ArrayList<WorkLog>();
    private WebMarkupContainer workLogListContainer;
    private AjaxTabbedPanel<AbstractTab> tabbedPanel;
    private Panel addPanel;

    public DailyWorkLogPage() {
        super(HELP_PANEL_TEXT);
        setOutputMarkupId(true);
        String loggedInUsername = (String) TimeTrackingWebSession.get().getAttribute(TimeTrackingWebSession.LOGIN_USERNAME_ATTR);
        User loggedInUser = TimeTrackingWebApplication.getService(UserService.class).findUserByUsername(loggedInUsername);
        workLogUIModel = new WorkLogUIModel(loggedInUser.getEmployee());
        initializeWorkLogModelWithLatestLoggedEntry();
        initComponents();

    }

    public DailyWorkLogPage(Employee employee, Calendar date) {
        super(HELP_PANEL_TEXT);

        setOutputMarkupId(true);
        workLogUIModel = new WorkLogUIModel(employee);
        initializeWorkLogModelWithLatestLoggedEntry();
        TimeTrackingWebSession.getSession().setSelectedDay(date);
        initComponents();
    }

    private void initComponents() {
        setOutputMarkupId(true);
        setOutputMarkupPlaceholderTag(true);

        buildWorkLogFormContainer();
        buildWorkLogListContainer();
        buildWorkLogFormComponents();
        buildAddEditPanel();
    }

    private void buildWorkLogFormContainer() {
        workLogFormContainer = new WebMarkupContainer("workLogFormContainer");
        workLogFormContainer.setOutputMarkupId(true);
        workLogFormContainer.setOutputMarkupPlaceholderTag(true);
        add(workLogFormContainer);
    }

    private void buildWorkLogListContainer() {
        workLogList.clear();
        if (workLogUIModel.getEmployee() != null) {
            loadWorkLogList();
        }

        workLogListContainer = new WebMarkupContainer("workLogListContainer"){
            @Override
            public void onConfigure() {
                setVisible(workLogList.size() > 0);
            }
        };

        DefaultDataTable<WorkLog> workLogListTable = new WorkLogTable("workLogList", workLogList, new DefaultWorkLogTableTemplate()) {

            @Override
            protected Item<WorkLog> newRowItem(final String id, final int index, final IModel<WorkLog> model)
            {
                Item<WorkLog> rowItem = super.newRowItem(id, index, model);
                rowItem.add(AttributeModifier.append("class", "clickable"));
                rowItem.add(new AjaxEventBehavior("onclick") {
                    @Override
                    protected void onEvent(AjaxRequestTarget target) {
                        createEditTabFor(target, model.getObject());
                    }
                });
                return rowItem;
            }
        };
        workLogListContainer.add(workLogListTable);
        workLogListContainer.setOutputMarkupId(true);
        workLogListContainer.setOutputMarkupPlaceholderTag(true);
        add(workLogListContainer);
    }

    private void buildWorkLogFormComponents() {
        workLogFormContainer.add(getTitleLabel(TimeTrackingWebSession.getSession().getSelectedDay()));
        workLogFormContainer.add(createNextDayLink());
        workLogFormContainer.add(createPreviousDayLink());

        EmployeeSelectionPanel employeeSelectionPanel = new EmployeeSelectionPanel(
                "employeeSelectionPanel", workLogUIModel, getOnSelectAction(), "pages.dailyWorkLogPage.form.employee", false);
        workLogFormContainer.add(employeeSelectionPanel);
    }

    private void buildAddEditPanel() {
        tabbedPanel = new AjaxTabbedPanel<AbstractTab>("addEditTabs", createAddEditTabsPanel());
        tabbedPanel.setOutputMarkupId(true);
        add(tabbedPanel);
    }

    private List<AbstractTab> createAddEditTabsPanel() {
        List<AbstractTab> tabs = new ArrayList<AbstractTab>();

        tabs.add(new AbstractTab(new ResourceModel(ADD_WORK_LOG_TAB_TITLE)) {

            @Override
            public WebMarkupContainer getPanel(String panelId) {
                workLogUIModel.resetWorkLog();
                addPanel =  new DailyWorkLogPanel(panelId, workLogUIModel, workLogList, false, getOnSaveAction());
                return addPanel;
            }
        });

        tabs.add(new AbstractTab(new ResourceModel(EDIT_WORK_LOG_TAB_TITLE)) {

            @Override
            public WebMarkupContainer getPanel(String panelId) {
                getPageParameters().clearNamed();
                return new NoSelectionPanel(panelId, "pages.dailyWorkLogPage.edit.noSelection");
            }
        });

        return tabs;
    }

    private UserInputCallableAction<Employee> getOnSelectAction() {
        return new UserInputCallableAction<Employee>() {

            @Override
            public void call(AjaxRequestTarget target, Employee selectedValue) {
                workLogUIModel = new WorkLogUIModel(selectedValue);
                initializeWorkLogModelWithLatestLoggedEntry();
                updateWorkLogListAndTabbedPanel(target);
                target.add(DailyWorkLogPage.this);
            }
        };
    }

    private UserInputCallableAction<String> getOnSaveAction() {
        return new UserInputCallableAction<String>() {
            @Override
            public void call(AjaxRequestTarget target, String feedback) {
                updateWorkLogListAndTabbedPanel(target);
                addPanel.info(feedback);
                target.add(tabbedPanel);
            }
        };
    }

    private void updateWorkLogListAndTabbedPanel(AjaxRequestTarget target) {
        remove(workLogListContainer);
        remove(tabbedPanel);
        buildWorkLogListContainer();
        buildAddEditPanel();
        target.add(this);
    }

    private void loadWorkLogList() {
        workLogList.clear();
        WorkLogService workLogService = TimeTrackingWebApplication.getService(WorkLogService.class);

        List<WorkLog> workLogListFromDB = workLogService.loadWorkLogForDateAndEmployee(workLogUIModel.getEmployee(),
                TimeTrackingWebSession.getSession().getSelectedDay().getTime());
        if (workLogListFromDB != null) {
            workLogList.addAll(workLogListFromDB);
        }
    }

    private void initializeWorkLogModelWithLatestLoggedEntry() {
        if (workLogUIModel.getEmployee() != null) {
            WorkLogService workLogService = TimeTrackingWebApplication.getService(WorkLogService.class);
            WorkLog latestWorkLog = workLogService.loadLatestWorkLogForEmployee(workLogUIModel.getEmployee());
            if (latestWorkLog == null) {
                return;
            }
            workLogUIModel.setProject(latestWorkLog.getProject());
            workLogUIModel.setSfi(latestWorkLog.getSfi());
            workLogUIModel.setShift(latestWorkLog.getShift());
            workLogUIModel.setWorkplace(latestWorkLog.getWorkplace());
            workLogUIModel.setWorkDetail(latestWorkLog.getWorkDetail());
            workLogUIModel.setHours(latestWorkLog.getHours());
        }
    }

    private Label getTitleLabel(Calendar selectedDay) {
        int dayOfWeek = selectedDay.get(Calendar.DAY_OF_WEEK);
        String dayOfWeekName = new ResourceModel(CalendarUtils.getDayOfWeekResourceKey(dayOfWeek)).getObject();
        int dayOfMonth = selectedDay.get(Calendar.DAY_OF_MONTH);
        int month = selectedDay.get(Calendar.MONTH);
        String monthName = new ResourceModel(CalendarUtils.getMonthResourceKey(month)).getObject();
        int year = selectedDay.get(Calendar.YEAR);
        StringBuilder label = new StringBuilder(dayOfWeekName).append(", ").append(dayOfMonth).append(" ").append(monthName).append(" ").append(year);
        return new Label("title", label.toString());
    }

    public void refreshPanel(AjaxRequestTarget ajaxRequestTarget) {
        this.remove(workLogFormContainer);
        this.remove(tabbedPanel);
        this.remove(workLogListContainer);

        initComponents();

        ajaxRequestTarget.add(this);
    }

    private void createEditTabFor(AjaxRequestTarget target, final WorkLog selectedWorklog) {
        tabbedPanel.getTabs().remove(1);
        tabbedPanel.getTabs().add(1, new AbstractTab(new ResourceModel(EDIT_WORK_LOG_TAB_TITLE)) {

            @Override
            public WebMarkupContainer getPanel(String panelId) {
                workLogUIModel = new WorkLogUIModel(selectedWorklog);
                return new DailyWorkLogPanel(panelId, workLogUIModel, workLogList, true, getOnSaveAction());
            }
        });
        tabbedPanel.setSelectedTab(1);
        target.add(tabbedPanel);
    }

    private AjaxLink<Void> createNextDayLink() {
        ChangeDayLink link = new ChangeDayLink("nextDayLink", 1);
        link.add(new Image("nextDayImg", new ContextRelativeResource("images/icon_set/16/Arrow3-Right.png")));
        return link;
    }

    private AjaxLink<Void> createPreviousDayLink() {
        ChangeDayLink link = new ChangeDayLink("previousDayLink", -1);
        link.add(new Image("previousDayImg",  new ContextRelativeResource("images/icon_set/16/Arrow3-Left.png")));
        return link;
    }

    class ChangeDayLink extends AjaxLink<Void> {
        private int dateChange;

        public ChangeDayLink(String id, int dateChange) {
            super(id);
            this.dateChange = dateChange;
        }

        @Override
        public void onClick(AjaxRequestTarget target) {
            Calendar selectedDay = TimeTrackingWebSession.getSession().getSelectedDay();
            selectedDay.add(Calendar.DATE, dateChange);
            TimeTrackingWebSession.getSession().setSelectedDay(selectedDay);
            refreshPanel(target);
        }
    }
}
